/*-*-C-*-
 * Window toolbars dialogue box for Windows CSE
 */

#include "resed.h"
#include "main.h"

#include "swicall.h"
#include "wimp.h"
#include "resformat.h"
#include "newmsgs.h"
#include "dbox.h"
#include "registry.h"

#include "format.h"
#include "windowedit.h"
#include "gui.h"
#include "icondefs.h"
#include "protocol.h"
#include "toolbars.h"


static WindowPtr toolbarsdboxproto;
static int toolbarsdboxsize;



/*
 * Load any templates required - called from load_prototypes(..) in main.c
 */

error * toolbars_load_prototypes (void)

{
    return wimp_load_template_returning_size (
                  "Toolbars", &toolbarsdboxproto, &toolbarsdboxsize);
}


/*
 * Called by toolbars_dbox_mouse_click(..) or toolbars_dbox_key_pressed(..)
 *  after the user has indicated that he wishes to apply the contents of the
 *  dbox.
 */

static error * apply_dbox (WindowObjPtr window, Bool stayopen)
{
    WindowPtr dbox = window->toolbarsdbox;
    char *oldibl = NULL;
    char *olditl = NULL;
    char *oldebl = NULL;
    char *oldetl = NULL;

    /* make a copy of the current state before proceeding */
    if (window->toolbaribl != NULL)
    {
        oldibl = copystring (window->toolbaribl);
        if (oldibl == NULL)
            goto nomem;
    }
    if (window->toolbaritl != NULL)
    {
        olditl = copystring (window->toolbaritl);
        if (olditl == NULL)
            goto nomem;
    }
    if (window->toolbarebl != NULL)
    {
        oldebl = copystring (window->toolbarebl);
        if (oldebl == NULL)
            goto nomem;
    }
    if (window->toolbaretl != NULL)
    {
        oldetl = copystring (window->toolbaretl);
        if (oldetl == NULL)
            goto nomem;
    }

 
    gui_get_opt_str (dbox, I_TOOLBARS_HASIBL, I_TOOLBARS_IBL,
                           &window->toolbaribl);
    gui_get_opt_str (dbox, I_TOOLBARS_HASITL, I_TOOLBARS_ITL,
                           &window->toolbaritl);
    gui_get_opt_str (dbox, I_TOOLBARS_HASEBL, I_TOOLBARS_EBL,
                           &window->toolbarebl);
    gui_get_opt_str (dbox, I_TOOLBARS_HASETL, I_TOOLBARS_ETL,
                           &window->toolbaretl);

    if (!equalstrings (oldibl, window->toolbaribl) ||
        !equalstrings (olditl, window->toolbaritl) ||
        !equalstrings (oldebl, window->toolbarebl) ||
        !equalstrings (oldetl, window->toolbaretl) )
    {
        /* inform shell that window object has been modified */
        protocol_send_resed_object_modified (window);
    }

    free (oldibl);
    free (olditl);
    free (oldebl);
    free (oldetl);

    /* redisplay Toolbars dbox if ADJ click - otherwise destroy it */
    if (stayopen)
        return toolbars_update_dbox (window, TRUE, FALSE);
    else
        return toolbars_close_dbox (window);

  nomem:             /* run out of memory */
    free (oldibl);
    free (olditl);
    free (oldebl);
    free (oldetl);
    return error_lookup ("NoMem");
}


/*
 * Update contents of dialogue box - only called if dialogue box exists.
 *
 * Called from windowedit_rename_window(..) - when the object is renamed.
 *        from windowedit_load(..) - when a new version of the object is
 *                                    force loaded [not at present]
 *        from apply_dbox(..) - if the toolbars dbox is to remain on view
 *        from toolbars_open_dbox(..) - after the dbox is created
 *        from toolbars_dbox_mouse_click(..) - after an ADJ-CANCEL click
 */

error * toolbars_update_dbox (
    WindowObjPtr window,
    Bool contents,
    Bool title
)
{
    WindowPtr dbox = window->toolbarsdbox;

    if (contents)
    {
        gui_put_opt_str (dbox, I_TOOLBARS_HASIBL, I_TOOLBARS_IBL,
                               window->toolbaribl);
        gui_put_opt_str (dbox, I_TOOLBARS_HASITL, I_TOOLBARS_ITL,
                               window->toolbaritl);
        gui_put_opt_str (dbox, I_TOOLBARS_HASEBL, I_TOOLBARS_EBL,
                               window->toolbarebl);
        gui_put_opt_str (dbox, I_TOOLBARS_HASETL, I_TOOLBARS_ETL,
                               window->toolbaretl);
    }

    if (title)
    {
        /* Get the printf pattern from the prototype's titlebar which
         * should have %s in it where the name is wanted
         */
        char buf[256];
        sprintf (buf, dbox_gettitle (toolbarsdboxproto), window->name);
        ER ( dbox_settitle (dbox, buf, TRUE) );
    }

    return NULL;
}


/*
 * Called from:
 *  windowedit_menu_cb(..) - when "Toolbars..." is chosen;
 *
 * If the corresponding toolbars dbox is already open, it is simply raised
 *  to the top of the window stack.
 *
 * Otherwise, a new toolbars window is created and opened.
 *
 * Any new window will be displayed at the same position as the most recent
 *  position of any other window created from the "toolbars" template;
 *  this is achieved by copying co-ordinates to the template whenever an
 *  existing window is reopened - see toolbars_reopen_dbox(..).
 */

error * toolbars_open_dbox (WindowObjPtr window)
{
    if (window->toolbarsdbox == NULL)
    {
        ER ( wimp_copy_template (toolbarsdboxproto,
                                 &window->toolbarsdbox, toolbarsdboxsize) );
        ER ( swi (Wimp_CreateWindow,  R1, &window->toolbarsdbox->visarea,
                        OUT,  R0, &window->toolbarsdbox->handle,  END) );
        ER ( registry_register_window (window->toolbarsdbox->handle,
                                       ToolbarsDbox, (void *) window) );
        window->toolbarsdbox->behind = -1;
        ER ( swi (Wimp_OpenWindow,  R1, window->toolbarsdbox,  END) );
        ER ( toolbars_update_dbox (window, TRUE, TRUE) );
    }
    else
    {
        window->toolbarsdbox->behind = -1;
        ER ( swi (Wimp_OpenWindow,  R1, window->toolbarsdbox,  END) );
    }   

    return dbox_set_caret_to (window->toolbarsdbox, I_TOOLBARS_ITL);
}


/*
 * Called from mouse_click(..) in main.c when the user clicks inside the
 *  dialogue box.
 */

error * toolbars_dbox_mouse_click (
    MouseClickPtr mouse,
    unsigned int modifiers,
    WindowObjPtr window
)
{
    int buttons = mouse->buttons;
    int icon = mouse->iconhandle;
    WindowPtr dbox = window->toolbarsdbox;
    Bool adjustclick = (buttons == MB_CLICK(MB_ADJUST));
    error *err = NULL;
    int valicon;

    if (buttons == MB_CLICK(MB_SELECT) || buttons == MB_CLICK(MB_ADJUST))
    {
        switch (icon)
        {
        case I_TOOLBARS_CANCEL:
            if (!adjustclick)
                return toolbars_close_dbox (window);
            else
                err = toolbars_update_dbox (window, TRUE, FALSE);
            break;

        case I_TOOLBARS_OK:
            err = apply_dbox (window, adjustclick);
            if (!adjustclick)
                return err;
            break;

        case I_TOOLBARS_HASIBL:
            valicon = I_TOOLBARS_IBL;
            goto cont;
        case I_TOOLBARS_HASITL:
            valicon = I_TOOLBARS_ITL;
            goto cont;
        case I_TOOLBARS_HASEBL:
            valicon = I_TOOLBARS_EBL;
            goto cont;
        case I_TOOLBARS_HASETL:
            valicon = I_TOOLBARS_ETL;
          cont:
            GUI_TOGGLE_FADE (dbox, valicon);
            if ( (dbox_getflags (dbox, valicon) & IF_SHADED) == 0 )
                dbox_place_caret (dbox, valicon);
            break;
        }
    }

    /* give input focus to the dbox regardless - but not in a faded icon */
    dbox_set_caret_to (dbox, -1);

    return err;
}


/*
 * Called from open_window_request(..) in main.c.
 *
 * Copies coordinates of current position to the prototype;
 *  see toolbars_open_dbox(..) above.
 */

error * toolbars_reopen_dbox (WindowPtr win, WindowObjPtr window)
{
    window->toolbarsdbox->visarea =
                       toolbarsdboxproto->visarea = win->visarea;
    window->toolbarsdbox->scrolloffset =
                       toolbarsdboxproto->scrolloffset = win->scrolloffset;
    window->toolbarsdbox->behind = win->behind;
    return swi (Wimp_OpenWindow, R1, window->toolbarsdbox, END);

    return NULL;
}


/*
 * Called from:
 *   close_window_request(..) in main.c - when the user clicks on the
 *          dialogue box's close icon.
 *   apply_dbox(..) -  after the new contents have been processed.
 *   toolbars_dbox_mouse_click(..) -  after a SEL-CANCEL click.
 *   windowedit_close_window(..) - when closing the parent editing window.
 *
 * The dialogue box is deleted.
 */

error * toolbars_close_dbox (WindowObjPtr window)
{
    WindowPtr toolbarsdbox = window->toolbarsdbox;

    ER ( registry_deregister_window (toolbarsdbox->handle) );

    /*
     * This service call is fielded by BorderUtils 0.05 which fixes
     *  a bug associated with the deletion of windows which have pressed-in
     *  slabbed icons in wimps before 3.17
     */

    ER ( swi (OS_ServiceCall, R0, toolbarsdbox->handle,
                              R1, 0x44ec5,
                              R2, taskhandle, END) );

    ER ( swi (Wimp_DeleteWindow,  R1, toolbarsdbox,  END) );
    free ((char *) toolbarsdbox);
    window->toolbarsdbox = NULL;

    return windowedit_focus_claim (window);
}


/*
 * Called from key_pressed(..) in main(..), when the user depresses a key
 *  when the dialogue box has the input focus.
 */

error * toolbars_dbox_key_pressed (
    WindowObjPtr window,
    KeyPressPtr key,
    Bool *consumed
)
{
    Bool keepopen = (wimp_read_modifiers() & MODIFIER_SHIFT) != 0;
    error *err = NULL;

    if (key->code == 13)         /* RETURN */
    {
        *consumed = TRUE;
        err = apply_dbox (window, keepopen);
        if (!keepopen)
            return err;
    }

    else if (key->code == 0x1b)  /* ESCAPE */
    {
        *consumed = TRUE;
        if (!keepopen)
            return toolbars_close_dbox (window);
        else
            err = toolbars_update_dbox (window, TRUE, FALSE);
    }

    /* ensure caret is not inside a faded icon */
    dbox_set_caret_to (window->toolbarsdbox, -1);

    return err;
}


/*
 * Returns TRUE if 'icon' is an acceptable place to drop an object onto in
 *  a toolbars dialogue box.
 *
 * Called from protocol_send_resed_object_name_request(..).
 */

Bool toolbars_drop_icon (
    int icon
)
{
    switch (icon)
    {
    case I_TOOLBARS_HASIBL:
    case I_TOOLBARS_HASITL:
    case I_TOOLBARS_HASEBL:
    case I_TOOLBARS_HASETL:
    case I_TOOLBARS_IBL:
    case I_TOOLBARS_ITL:
    case I_TOOLBARS_EBL:
    case I_TOOLBARS_ETL:
        return TRUE;
    }

    return FALSE;
}


/*
 * Called to process an object of class 'class', name 'name', dropped onto
 *  icon 'icon' in the toolbars dbox of 'window'.
 *
 * Called from received_resed_object_name(..) in c.protocol.
 */

error * toolbars_object_drop (
    WindowObjPtr window,
    int icon,
    ObjectClass class,
    char *name
)
{
    WindowPtr dbox = window->toolbarsdbox;

    /* it would be nice if we could check the Toolbar flag, but the best we
       can do is to check that it's a window object */
    if (class != WINDOW_OBJECT_CLASS)
        return error_lookup ("BadDrop");

    switch (icon)
    {
    case I_TOOLBARS_HASIBL:
    case I_TOOLBARS_IBL:
        return gui_put_opt_str (dbox, I_TOOLBARS_HASIBL, I_TOOLBARS_IBL,
                                name);
    case I_TOOLBARS_HASITL:
    case I_TOOLBARS_ITL:
        return gui_put_opt_str (dbox, I_TOOLBARS_HASITL, I_TOOLBARS_ITL,
                                name);
    case I_TOOLBARS_HASEBL:
    case I_TOOLBARS_EBL:
        return gui_put_opt_str (dbox, I_TOOLBARS_HASEBL, I_TOOLBARS_EBL,
                                name);
    case I_TOOLBARS_HASETL:
    case I_TOOLBARS_ETL:
        return gui_put_opt_str (dbox, I_TOOLBARS_HASETL, I_TOOLBARS_ETL,
                                name);
    }

    return NULL;
}
